/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package tos.tasprep;

import java.util.Random;
import org.jdesktop.application.FrameView;
import tos.TosView;

/**
 *
 * @author Milos
 */
public class Processes extends Thread {
    // Deljena promenjiva koja se povecava

    private Brojac counter;
    // promenljiva koja pokazuje koliko puta treba povecati brojac
    int noOfIncrements;
    // random broj
    private Random r;
    // seed random broj
    private long seed;
    // identifikacioni broj procesa
    private int processID;
    private Variables vars;
    private boolean cannot;
    private FrameView parent;

    // Konstruktor
    public Processes(int processID, Brojac counter, int noOfIncrements, Variables vars, FrameView parent) {
        this.processID = processID;
        this.counter = counter;
        this.noOfIncrements = noOfIncrements;
        this.vars = vars;
        this.parent = parent;
        Random temp = new Random();
        seed = temp.nextLong();
        r = new Random(seed);
        cannot = true;
    }

    // Metada koja uspavljuje nit na slucajan broj milisekundi izmedju 0 i 1000
    public void busy() {
        int pause = (int) (r.nextDouble() * 1000);

        try {
            sleep(pause);
        } catch (InterruptedException ex) {
            System.out.println("Erorr!!" + ex.toString());
        }
    }

    public int getNext(int i) {
        int j = 0;

        if (i == vars.getNoOfProcesses() - 1) {
            j = 0;
        } else {
            j = i + 1;
        }

        return j;
    }

    // Metoda koja opisuje ne kriticnu sekciju
    public void nonCritical() {
        //System.out.println ("Proces p" + processID + " ulazi u nekriticnu sekciju.");
        ((TosView)parent).appendOutput("Proces p" + processID + " ulazi u nekriticnu sekciju.\n");
        //busy();
        //System.out.println ("Proces p" + processID + " izlazi iz nekriticne sekcije.");
        ((TosView)parent).appendOutput("Proces p" + processID + " izlazi iz nekriticne sekcije.\n");
    }

    // Metoda koja opisuje rutine pre ulaska u kriticnu sekciju
    public void preCritical() {
        cannot = true;
        vars.setWait(processID, true);
        while (vars.getWait(processID) && cannot) {
            setCannot(vars.TAS(vars.isForbiden()));
        }
        vars.setWait(processID, false);
    }

    // Metoda koja opisuje rutine posle ulaska u kriticnu sekciju
    public void postCritical() {
        int j = getNext(processID);
        while (j != processID && !vars.getWait(j)) {
            j = getNext(j);
        }

        if (j == processID) {
            vars.setForbiden(false);
        } else {
            vars.setWait(j, false);
        }
    }

    // Metoda koja opisuje kriticnu sekciju
    public void critical() {
        System.out.println("Proces p" + processID + " ulazi u kriticnu sekciju.");
        ((TosView)parent).appendOutput("Proces p" + processID + " ulazi u kriticnu sekciju.\n");
        //busy();
        int temp = counter.getBroj();
        temp++;
        counter.setBroj(temp);
        System.out.println("Proces p" + processID + " izlazi iz kriticne sekcije.");
        ((TosView)parent).appendOutput("Proces p" + processID + " izlazi iz kriticne sekcije.\n");
    }

    public boolean isCannot() {
        return cannot;
    }

    public synchronized void setCannot(boolean cannot) {
        this.cannot = cannot;
    }

    // Run metoda
    @Override
    public void run() {
        for (int i = 0; i < noOfIncrements; i++) {
            nonCritical();
            preCritical();
            critical();
            postCritical();
        }
    }
}
